﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Threading;
using ZMenFM.Network;
using ZMenFM.Network.Spider;

namespace ZMenFM.Network.Song
{
    public enum LrcLoadStatus
    {
        LLS_LOADING,
        LLS_LOAD_OK,
        LLS_LOAD_FAILED
    }

    public enum SongLoadStatus
    {
        SLS_NOT_START,
        SLS_LOADING,
        SLS_LOAD_OK,
        SLS_LOAD_FAILED
    }

    /// <summary>
    /// 歌曲数据类
    /// </summary>
    public class SongData
    {
        public String SongUrl;
        public String LrcID;
        public String LrcUrl;
        public int Flag;
        public int Type;
        public LrcData LrcContent;

        public override string ToString()
        {
            String str = "{ \"SongUrl\": " + "\"" + SongUrl + "\"";
            str += ", \"LrcID\": ";
            str += LrcID;
            str += ", \"LrcUrl\": ";
            str += ("\"" + LrcUrl + "\"");
            str += ", \"Flag\": ";
            str += Flag.ToString();
            str += ", \"Type\": ";
            str += Type.ToString();
            str += " }";

            return str;
        }
    }

    public class LrcData
    {
        private String Url;                     //歌词Url
        private String Lrc;                     //lrc歌词内容
        private LrcLoadStatus LoadStatus;       //加载状态
        private Thread LoadLrcThread;           //加载歌词的线程
        private ZMSpider Spider;                //爬虫
        private Object Lockwho;                 //用来异步执行的一个媒介

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="url">歌词文件地址</param>
        public LrcData(String url)
        {
            Lockwho = new object();
            Spider = new ZMSpider();
            Spider.InitContext(true, "$", false);
            Url = url;
            Lrc = "";
            LoadStatus = LrcLoadStatus.LLS_LOADING;

            LoadLrcThread = new Thread(new ThreadStart(_LoadLrc));
            LoadLrcThread.Start();
        }

        /// <summary>
        /// 读取歌词文件线程函数
        /// </summary>
        private void _LoadLrc()
        {
            Spider.ClearGetData();
            Spider.ClearPostData();
            String lrc = Spider.Get(Url, ZMSpiderCodec.VJCD_GB2312, ZMSpiderCookie.VJUCT_NO_COOKIE).Trim();
            Spider.ClearGetData();
            Spider.ClearPostData();

            if (lrc == "")
            {
                Lrc = "";
                lock (Lockwho)
                {
                    LoadStatus = LrcLoadStatus.LLS_LOAD_FAILED;
                }
                return;
            }

            if (lrc[0] == '<')
            {
                lock(Lockwho)
                {
                    LoadStatus = LrcLoadStatus.LLS_LOAD_FAILED;
                }
                return;
            }

            lock (Lockwho)
            {
                Lrc = lrc;
                LoadStatus = LrcLoadStatus.LLS_LOAD_OK;
            }
        }

        /// <summary>
        /// 获取载入状态
        /// </summary>
        /// <returns></returns>
        public LrcLoadStatus GetStatus()
        {
            LrcLoadStatus s;
            lock (Lockwho)
            {
                s = LoadStatus;
            }
            return s;
        }

        /// <summary>
        /// 返回歌词
        /// </summary>
        /// <returns></returns>
        public String GetLrcString()
        {
            String lrc;
            lock (Lockwho)
            {
                lrc = Lrc;
            }
            return lrc;
        }
    }

    /// <summary>
    /// 歌曲物品类
    /// </summary>
    public class SongItem
    {
        protected SongLoadStatus LoadStatus;    //加载状态

        protected Thread ParseThread;

        protected String SongName;      //歌曲名称
        protected String Artist;        //歌手
        protected String Extra;         //附加信息

        private List<SongData> SongList = new List<SongData>(); //貌似是这样的，一个SongItem对应一个列表的SongData。一首歌有不同的地址。
        protected int CurrentDataIndex;     //当前歌曲地址列表的索引

        private Object Lockwho;             //异步执行的媒介
        private ZMSpider Spider;            //爬虫
        //构造函数
        public SongItem(String name, String art, String ext)
        {
            SongName = name;
            Artist = art;
            Extra = ext;
            Lockwho = new Object();
            Spider = new ZMSpider();
            Spider.InitContext(true, "$", false);
            LoadStatus = SongLoadStatus.SLS_NOT_START;

            //ParseThread = new Thread(new ThreadStart(ParseSongData));
            //ParseThread.Start();
        }

        /// <summary>
        /// 获取歌曲信息载入状态
        /// </summary>
        /// <returns>载入状态</returns>
        public SongLoadStatus GetLoadStatus()
        {
            SongLoadStatus s;
            lock (Lockwho)
            {
                s = LoadStatus;
            }
            return s;
        }

        /// <summary>
        /// 载入歌曲信息
        /// </summary>
        public void Load()
        {
            /** 若已经正在载入则不用多余之举 */
            if (LoadStatus == SongLoadStatus.SLS_LOADING) return;

            /** 启动载入线程 */
            lock (Lockwho)
            {
                LoadStatus = SongLoadStatus.SLS_LOADING;
            }

            ParseThread = new Thread(new ThreadStart(ParseSongData));
            ParseThread.Start();
        }

        /// <summary>
        /// 分析歌曲数据线程函数
        /// </summary>
        protected void ParseSongData()
        {
            CurrentDataIndex = 0;

            /** GET值 */
            String titleVar = SongName + "$$" + Artist + "$$" + Extra + "$$";
            String fromVar = ZMNetworkGlobal.FromVar;
            String randVar = new Random().NextDouble().ToString();          //其实我一直很不理解，这个随机数是用来干嘛的。郁闷

            /** 数据 */
            Spider.ClearGetData();
            Spider.ClearPostData();
            Spider.PushGetData("title", titleVar);
            Spider.PushGetData("from", fromVar);
            Spider.PushGetData(".r", randVar);          //在http协议包中加入一个随机数和一个from，貌似是百度要求这样做的。
            

            /** 获取数据 */
            String SongXMLStr = Spider.Get(ZMConstUrl.songDataUrl, ZMSpiderCodec.VJCD_GB2312, ZMSpiderCookie.VJUCT_NO_COOKIE);

            /** 输出数据 */
            //Console.WriteLine(SongXMLStr.Substring(0, SongXMLStr.Length - 1));

            /** 清理数据 */
            Spider.ClearGetData();
            Spider.ClearPostData();

            /** 分析XML */
            CurrentDataIndex = -1;
            try
            {
                for (int i = SongXMLStr.Length - 1; i >= 0; i--)
                {
                    if (SongXMLStr[i] == '>')
                    {
                        SongXMLStr = SongXMLStr.Substring(0, i + 1);
                        break;
                    }
                }

                XmlDocument doc = new XmlDocument();
                doc.LoadXml(SongXMLStr);

                XmlNode root = doc.FirstChild.NextSibling;

                /** 数量 */
                int count = Convert.ToInt32(root.FirstChild.InnerText);
                if (0 == count)
                {
                    lock (Lockwho)
                    {
                        //Console.WriteLine(SongName + " - " + Artist + " - " + Extra + " 分析完毕...");
                        LoadStatus = SongLoadStatus.SLS_LOAD_OK;
                    }
                    return;
                }

                XmlNode node = root.FirstChild.NextSibling;

                /** 循环获取歌曲信息 */
                for (int i = 0; i < count; i++)
                {
                    if (node.Name.ToLower() == "url")
                    {
                        _AddSong((XmlElement)node);
                        node = (XmlElement)node.NextSibling;
                    }
                    else
                    {
                        node = (XmlElement)node.NextSibling;
                        i--;
                    }
                }

                lock (Lockwho)
                {
                    //Console.WriteLine(SongName + " - " + Artist + " - " + Extra + " 分析完毕...");
                    LoadStatus = SongLoadStatus.SLS_LOAD_OK;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);

                lock (Lockwho)
                {
                    //Console.WriteLine(SongName + " - " + Artist + " - " + Extra + " 分析失败...");
                    LoadStatus = SongLoadStatus.SLS_LOAD_FAILED;
                }
            }
        }

        /// <summary>
        /// 添加歌曲
        /// </summary>
        /// <param name="node">url节点</param>
        private void _AddSong(XmlElement node)
        {
            if (!node.HasChildNodes) return;

            String encode = "";
            String decode = "";
            int type = 0;
            String lrcid = "";
            int flag = 0;

            /** 找出所有属性 */
            for (XmlElement n = (XmlElement)node.FirstChild; n != null; n = (XmlElement)n.NextSibling)
            {
                switch (n.Name.ToLower())
                {
                    case "encode":
                        encode = n.InnerText;
                        break;

                    case "decode":
                        decode = n.InnerText;
                        break;

                    case "type":
                        type = Convert.ToInt32(n.InnerText);
                        break;

                    case "lrcid":
                        lrcid = n.InnerText;
                        break;

                    case "flag":
                        flag = Convert.ToInt32(n.InnerText);
                        break;
                }
            }

            /** 分析属性 */
            SongData sd = new SongData();

            /** 找出Url目录 */
            int pos = encode.LastIndexOf('/');
            if (-1 == pos) return;
            String SongUrl = encode.Substring(0, pos + 1);
            SongUrl += decode;
            sd.SongUrl = SongUrl;

            /** Lrc地址 */
            if (lrcid.Length > 2)
            {
                String LrcUrl = ZMConstUrl.songLrcUrl;
                LrcUrl += lrcid.Substring(0, lrcid.Length - 2);
                LrcUrl += "/";
                LrcUrl += lrcid;
                LrcUrl += ".lrc";

                sd.LrcID = lrcid;
                sd.LrcUrl = LrcUrl;
                sd.LrcContent = new LrcData(sd.LrcUrl);
            }

            sd.Flag = flag;
            sd.Type = type;

            SongList.Add(sd);
        }

        #region 外部调用获取歌曲信息
        /// <summary>
        /// 第一个地址信息
        /// </summary>
        /// <returns>歌曲数据信息</returns>
        public SongData GetFirstItem()
        {
            if (SongList.Count == 0) return null;

            CurrentDataIndex = 0;
            return SongList[0];
        }

        /// <summary>
        /// 最后一个地址信息
        /// </summary>
        /// <returns>歌曲数据信息</returns>
        public SongData GetLastItem()
        {
            if (SongList.Count == 0) return null;

            CurrentDataIndex = SongList.Count - 1;
            return SongList[SongList.Count - 1];
        }

        /// <summary>
        /// 下一个地址信息
        /// </summary>
        /// <param name="Cycled">是否循环获取</param>
        /// <returns>歌曲数据信息</returns>
        public SongData GetNextItem(bool Cycled = false)
        {
            /** 非循环获取而且已经获取到了最后一个 */
            if (!Cycled && CurrentDataIndex == SongList.Count - 1) return null;
            if (SongList.Count == 0) return null;

            CurrentDataIndex = (CurrentDataIndex + 1) % SongList.Count;
            return SongList[CurrentDataIndex];
        }

        /// <summary>
        /// 上一个地址信息
        /// </summary>
        /// <param name="Cycled">是否循环获取</param>
        /// <returns>歌曲数据信息</returns>
        public SongData GetPrevItem(bool Cycled = false)
        {
            /** 非循环获取而且已经获取到了第一个 */
            if (!Cycled && CurrentDataIndex == 0) return null;
            if (SongList.Count == 0) return null;

            CurrentDataIndex = CurrentDataIndex - 1;
            if (CurrentDataIndex == -1) CurrentDataIndex = SongList.Count - 1;

            return SongList[CurrentDataIndex];
        }
        #endregion

        public override string ToString()
        {
            String str = SongName + " - " + Artist + " - " + Extra + ": ";
            if (SongList.Count == 0) str += "null";
            else str += SongList[0].ToString();

            return str;
        }
    }
}
